﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Timers;

using Includes;

namespace AsyncroneModule
{
   class AsyncroneModule
   {
      static void Main(string[] args)
      {
         // Set up sms reader
         Timer t1 = new Timer();
         t1.Interval = (5 * 1000);
         t1.Elapsed += new ElapsedEventHandler(processNewSMSes);
         t1.AutoReset = true;
         
         while(!GSMComWrapper.init(6, 9600, 500));
         
         t1.Start();
         Console.WriteLine("Ready");

         while (true)
         {
            System.Threading.Thread.Sleep((int)(30000));
         }
      }


      static bool running = false;

      /// <summary>
      /// Processes all SMS that have been received, but not been processed yet
      /// </summary>
      static private void processNewSMSes(Object eventSource, EventArgs eventArguments)
      {
         // If SMS are being processed already, ignore
         if (running)
            return;

         // Block additional worker threads
         running = true;

         SMS[] incomingSMSList;

         try
         {
            incomingSMSList = GSMComWrapper.receiveSMSes();
         }
         catch(Exception)
         {
            // No readable SMS detected
            running = false;
            return;
         }


         SMS currentSMS; 
         SMS answerSMS;
         CallInfoAsync currentResult;

         // Process all received SMSes
         foreach(SMS incomingSMS in incomingSMSList)
         {
            Console.Write("Processing: {0}: {1}\n", incomingSMS.senderNumber, incomingSMS.text);
            currentSMS = incomingSMS;
             
            // Check if sms is asyncronous system event
            if(currentSMS.text.Contains("CAW+"))
            {
               try
               {
                  String[] sep = {"CAW+"};
                  String[] tmp = currentSMS.text.Split(sep,System.StringSplitOptions.RemoveEmptyEntries);

                  String patientID = Parser.parseSMSSenderNumber('+'+tmp[1]);
                  
                  // Create event file
                  System.IO.Directory.CreateDirectory("Info");
                  System.IO.File.Create("Info\\"+patientID);

                  Console.WriteLine("Event SMS translated");

                  GSMComWrapper.deleteSMSbyId(currentSMS.ID);
               }
               catch(Exception)
               {
                  Console.WriteLine("Event SMS could not be translated");
               }
               continue;
            }

            // Check if sms can be used (sender number / caller id)
            try
            {
               currentSMS.senderNumber = Parser.parseSMSSenderNumber(currentSMS.senderNumber);
            }
            catch(CouldNotParseException)
            {
               // Sms can not be mapped, discard it (Sending an answer isn't possible for obvious reasons)
               Console.WriteLine("Sender could not be parsed, SMS discarded");
               GSMComWrapper.deleteSMSbyId(currentSMS.ID);
               continue;
            }

            // Define Answer sms (except for message)
            answerSMS = new SMS();
            answerSMS.receipientNumber = currentSMS.senderNumber;
            answerSMS.senderNumber     = "+490123456789"; // ignored anyway

            // Parse the incomig SMS text to Vitals
            Vitals vitals;
            try
            {
               vitals = Parser.ParseSMStoVitals(currentSMS);
            }
            catch (CouldNotParseException)
            {
               Console.WriteLine("Vitals could not be parsed");
               answerSMS.text = Messages.FP0001;

               sendAnswerAndDeleteSMSIfAnswerWasSuccessfullySend(answerSMS, currentSMS);

               continue;
            }


            // Plausibility check the parsed values
            if (!PlausibilityCheck.isPlausible(vitals))
            {
               Console.WriteLine("Vitals are not plausible");
               answerSMS.text = Messages.FP0001;

               sendAnswerAndDeleteSMSIfAnswerWasSuccessfullySend(answerSMS, currentSMS);

               continue;
            }


            // Insert received SMS to database, and respond appropriately
            // SETTING THE KR FLAG IN CASE OF SUCCESSIVE DEVIATION HAS TO BE DONE IN THE INSERT VAL. ROUTINE
            currentResult = ValueCheck.insertValues(currentSMS.senderNumber, vitals);
            switch (currentResult.action)
            {
               // OKAY (No reaction)
               case (0):
                  GSMComWrapper.deleteSMSbyId(currentSMS.ID);
                  break;

               // Normal deviation
               case (-1):
                  Console.WriteLine("Deviation detected");
                  answerSMS.text = Messages.IP0002.Replace("<Name des Patienten>",currentResult.name); 
                  sendAnswerAndDeleteSMSIfAnswerWasSuccessfullySend(answerSMS, currentSMS);
                  break;

               // CRITICAL deviation
               case (-2):
                  Console.WriteLine("Critical deviaton detected");
                  answerSMS.text = Messages.INA0001.Replace("<Name des Patienten>", currentResult.name); 
                  sendAnswerAndDeleteSMSIfAnswerWasSuccessfullySend(answerSMS, currentSMS);
                  break;

               // Successiv deviation
               case (-3):
                  Console.WriteLine("Successive deviation detected");
                  answerSMS.text = Messages.IP0003.Replace("<Name des Patienten>", currentResult.name);
                  sendAnswerAndDeleteSMSIfAnswerWasSuccessfullySend(answerSMS, currentSMS);
                  break;

               // Active Patient with that number does not exist
               case (-9):
                  Console.WriteLine("Patient with this number does not exist");
                  answerSMS.text = "Your number is not recognized by the system";
                  sendAnswerAndDeleteSMSIfAnswerWasSuccessfullySend(answerSMS, currentSMS);
                  break;
                  
               // Unrecognized return value
               default:
                  Console.WriteLine("Undefined error while trying to evaluate");
                  break;
            }

            continue; //... yea its the end of the loop anyway, but who cares :P 
         }

         Console.WriteLine("Processing complete");

         running = false;

         return;
      }

      /// <summary>
      /// ... Yea, the title is quite clear
      /// </summary>
      /// <param name="answerSMS"> SMS to be send </param>
      /// <param name="smsToBeDeleted"> SMS to be deleted (ID will be used) </param>
      /// <returns> true if successful, false otherwise </returns>
      static private bool sendAnswerAndDeleteSMSIfAnswerWasSuccessfullySend(SMS answerSMS, SMS smsToBeDeleted)
      {
         if (GSMComWrapper.sendSMS(answerSMS))
         {
            GSMComWrapper.deleteSMSbyId(smsToBeDeleted.ID);
            return true;
         }
         else
         {
            Console.WriteLine("Answer SMS {0} {1} could not be sent, SMS not deleted!", answerSMS.receipientNumber, answerSMS.text);
            return false;
         }
      }
   }
}
